package zk.demo;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkMarshallingError;
import org.I0Itec.zkclient.serialize.ZkSerializer;
import org.apache.commons.dbcp2.BasicDataSource;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class jdbc_test {
    private static BasicDataSource dataSource;
    private static ZkClient zkClient;
    private static ObjectMapper mapper = new ObjectMapper();
    /**
     * 启动服务
     *
     * 1. 启动 web 容器
     * 2. 初始化 zookeeper
     * 3. 配置数据库连接池
     *
     */
    public static void main(String[] args) throws InterruptedException {



        zkClient = new ZkClient("192.168.86.100:2181");

        zkClient.setZkSerializer(new ZkStrSerializer());
        if (!zkClient.exists("/jdbc")) {
            zkClient.createPersistent("/jdbc", "{\"url\":\"jdbc:mysql://192.168.86.100:3306/mysql?useUnicode=true&useSSL=false\",\"username\":\"root\",\"password\":\"root\",\"driver\":\"com.mysql.jdbc.Driver\"}");
        }
        zkClient.subscribeDataChanges("/jdbc", new IZkDataListener() {

            public void handleDataChange(String path, Object data) throws SQLException {

                System.out.println(path + " data is changed, new data " + data);

                dataSource.close();

                getConfig();
            }

            public void handleDataDeleted(String path) throws SQLException {

                System.out.println(path + " is deleted!!");

                dataSource.close();
            }
        });
        getConfig();
       /* //更新节点的数据，删除节点，验证监听器是否正常运行
        final Object o = zkClient.readData("/jdbc");
        System.out.println(o);

        zkClient.writeData("/jdbc", "{\"url\":\"jdbc:mysql://192.168.86.100:3306/test?useUnicode=true&useSSL=false\",\"username\":\"root\",\"password\":\"root\",\"driver\":\"com.mysql.jdbc.Driver\"}");
        Thread.sleep(1000);
        //删除节点
        zkClient.delete("/jdbc");*/
        Thread.sleep(Integer.MAX_VALUE);
    }

    /**
     * 配置数据库连接池
     *
     * 1. 从 zookeeper 中获取配置信息
     * 2. 更新 hikari 配置
     * 3. 执行测试 sql
     */
    private static void getConfig(){

        JDBCConfig myConfig = getJDBCConfig();

        updateDataSource(myConfig);

        try {

            executeTestSQL();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static void executeTestSQL() throws SQLException {

        Connection connection = dataSource.getConnection();

        PreparedStatement pst = connection.prepareStatement( "SELECT id, name FROM dept;" );

        ResultSet rs = pst.executeQuery();

        while (rs.next()) {

            System.out.println("id : " + rs.getString(1) + " , name : " + rs.getString(2));
        }
    }

    private static void updateDataSource(JDBCConfig myConfig) {
        dataSource = new BasicDataSource();
        dataSource.setUrl(myConfig.getUrl());
        dataSource.setUsername(myConfig.getUsername());
        dataSource.setPassword(myConfig.getPassword());
        dataSource.setDriverClassName(myConfig.getDriver());
        dataSource.setMaxTotal(20);
    }

    private static JDBCConfig getJDBCConfig() {

        Object data = zkClient.readData("/jdbc");

        try {
            JDBCConfig myConfig = mapper.readValue(data.toString(), JDBCConfig.class);

            System.out.println(myConfig.toString());

            return myConfig;

        } catch (JsonProcessingException e) {

            return new JDBCConfig();
        }
    }
}

class ZkStrSerializer implements ZkSerializer {

    @Override
    public byte[] serialize(Object o) throws ZkMarshallingError {
        return String.valueOf(o).getBytes();
    }

    @Override
    public Object deserialize(byte[] bytes) throws ZkMarshallingError {
        return new String(bytes);
    }
}

class JDBCConfig {

    private String url;

    private String driver;

    private String username;

    private String password;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
